/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.core;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import javax.swing.*;
import org.openide.NotifyDescriptor;
import org.openide.DialogDescriptor;
import org.openide.TopManager;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
/** Default implementation of Dialog created from NotifyDescriptor.
*
* @author Ian Formanek, Jaroslav Tulach
*/
class NbPresenter extends JDialog
implements PropertyChangeListener, WindowListener {
/** variable holding current modal dialog in the system */
public static NbPresenter currentModalDialog;
protected NotifyDescriptor descriptor;
private final JButton stdYesButton = new JButton (NbBundle.getBundle (NbPresenter.class).getString ("YES_OPTION_CAPTION"));
private final JButton stdNoButton = new JButton (NbBundle.getBundle (NbPresenter.class).getString ("NO_OPTION_CAPTION"));
private final JButton stdOKButton = new JButton (NbBundle.getBundle (NbPresenter.class).getString ("OK_OPTION_CAPTION"));
private final JButton stdCancelButton = new JButton (NbBundle.getBundle (NbPresenter.class).getString ("CANCEL_OPTION_CAPTION"));
private final JButton stdHelpButton = new JButton (NbBundle.getBundle (NbPresenter.class).getString ("HELP_OPTION_CAPTION"));
private final JButton stdDetailButton = new JButton (NbBundle.getBundle (NbPresenter.class).getString ("HELP_OPTION_CAPTION"));
{
stdYesButton.setDefaultCapable (true);
stdOKButton.setDefaultCapable (true);
stdNoButton.setDefaultCapable (false);
stdCancelButton.setDefaultCapable (false);
stdHelpButton.setDefaultCapable (false);
stdDetailButton.setDefaultCapable (false);
}
private final static String CANCEL_COMMAND = "Cancel"; // NOI18N
private Component currentMessage;
private JPanel currentButtonsPanel;
private Component[] currentPrimaryButtons;
private Component[] currentSecondaryButtons;
/** useful only for DialogDescriptor */
private int currentAlign;
private ButtonListener buttonListener;
/** Help context to actually associate with the dialog, as it is currently known. */
private transient HelpCtx currentHelp = null;
/** Used to prevent updateHelp from calling initializeButtons too many times. */
private transient boolean haveCalledInitializeButtons = false;
static final long serialVersionUID =-4508637164126678997L;
/** Creates a new Dialog from specified NotifyDescriptor,
* with given frame owner.
* @param d The NotifyDescriptor to create the dialog from
*/
public NbPresenter (NotifyDescriptor d, Frame owner, boolean modal) {
super(owner, d.getTitle(), modal); // modal
initialize(d);
}
/** Creates a new Dialog from specified NotifyDescriptor,
* with given dialog owner.
* @param d The NotifyDescriptor to create the dialog from
*/
public NbPresenter (NotifyDescriptor d, Dialog owner, boolean modal) {
super(owner, d.getTitle(), modal); // modal
initialize(d);
}
private void initialize (NotifyDescriptor d) {
descriptor = d;
setDefaultCloseOperation (JDialog.DO_NOTHING_ON_CLOSE);
buttonListener = new ButtonListener ();
getRootPane().registerKeyboardAction (
buttonListener,
CANCEL_COMMAND,
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW
);
initializeMessage ();
updateHelp ();
initializeButtons ();
haveCalledInitializeButtons = true;
descriptor.addPropertyChangeListener (this);
addWindowListener (this);
pack ();
setLocationRelativeTo (null); // center on screen
}
private void initializeMessage () {
if (currentMessage != null) {
getContentPane ().remove (currentMessage);
}
Object message = descriptor.getMessage ();
if (
descriptor.getMessageType () == NotifyDescriptor.PLAIN_MESSAGE &&
(message instanceof Component)
) {
// if plain message => use directly the component
currentMessage = (Component)message;
getContentPane ().add (currentMessage, BorderLayout.CENTER);
} else {
currentMessage = createOptionPane ();
getContentPane ().add (currentMessage, BorderLayout.CENTER);
}
currentMessage.requestFocus();
}
/** Creates option pane message.
*/
private JOptionPane createOptionPane () {
Object msg = descriptor.getMessage();
if (msg instanceof String) {
msg = org.openide.util.Utilities.replaceString ((String)msg, "\t", " "); // NOI18N
msg = org.openide.util.Utilities.replaceString ((String)msg, "\r", ""); // NOI18N
}
// initilize component
JOptionPane optionPane = new JOptionPane(
msg,
descriptor.getMessageType(),
0, // options type
null, // icon
new Object[0], // options
null // value
);
optionPane.setWantsInput (false);
return optionPane;
}
protected final void initializeButtons () {
// -----------------------------------------------------------------------------
// If there were any buttons previously, remove them and removeActionListener from them
if (currentButtonsPanel != null) {
if (currentPrimaryButtons != null) {
for (int i = 0; i < currentPrimaryButtons.length; i++) {
modifyListener (currentPrimaryButtons[i], buttonListener, false);
}
}
if (currentSecondaryButtons != null) {
for (int i = 0; i < currentSecondaryButtons.length; i++) {
modifyListener (currentSecondaryButtons[i], buttonListener, false);
}
}
getContentPane ().remove (currentButtonsPanel);
}
Object[] primaryOptions = descriptor.getOptions ();
Object[] secondaryOptions = descriptor.getAdditionalOptions ();
currentAlign = getOptionsAlign ();
// -----------------------------------------------------------------------------
// Obtain main (primary) and additional (secondary) buttons
currentPrimaryButtons = null;
currentSecondaryButtons = null;
// explicitly provided options (AKA buttons)
// JST: The following line causes only problems,
// I hope that my change will not cause additional ones ;-)
// if (descriptor.getOptionType () == NotifyDescriptor.DEFAULT_OPTION) {
if (primaryOptions != null) {
currentPrimaryButtons = new Component [primaryOptions.length];
for (int i = 0; i < primaryOptions.length; i++) {
if (primaryOptions[i] == NotifyDescriptor.YES_OPTION) {
currentPrimaryButtons[i] = stdYesButton;
} else if (primaryOptions[i] == NotifyDescriptor.NO_OPTION) {
currentPrimaryButtons[i] = stdNoButton;
} else if (primaryOptions[i] == NotifyDescriptor.OK_OPTION) {
currentPrimaryButtons[i] = stdOKButton;
} else if (primaryOptions[i] == NotifyDescriptor.CANCEL_OPTION) {
currentPrimaryButtons[i] = stdCancelButton;
} else if (primaryOptions[i] instanceof Component) {
currentPrimaryButtons[i] = (Component) primaryOptions [i];
} else if (primaryOptions [i] instanceof Icon) {
JButton button = new JButton ((Icon)primaryOptions [i]);
currentPrimaryButtons[i] = button;
} else {
JButton button = new JButton (primaryOptions[i].toString ());
currentPrimaryButtons[i] = button;
}
}
} else { // predefined option types
switch (descriptor.getOptionType ()) {
case NotifyDescriptor.YES_NO_OPTION:
currentPrimaryButtons = new Component[2];
currentPrimaryButtons[0] = stdYesButton;
currentPrimaryButtons[1] = stdNoButton;
break;
case NotifyDescriptor.YES_NO_CANCEL_OPTION:
currentPrimaryButtons = new Component[3];
currentPrimaryButtons[0] = stdYesButton;
currentPrimaryButtons[1] = stdNoButton;
currentPrimaryButtons[2] = stdCancelButton;
break;
case NotifyDescriptor.OK_CANCEL_OPTION:
default:
currentPrimaryButtons = new Component[2];
currentPrimaryButtons[0] = stdOKButton;
currentPrimaryButtons[1] = stdCancelButton;
break;
}
}
// Automatically add a help button if needed.
if (currentHelp != null) {
if (currentPrimaryButtons == null) currentPrimaryButtons = new Component[] { };
Component[] cPB2 = new Component[currentPrimaryButtons.length + 1];
System.arraycopy (currentPrimaryButtons, 0, cPB2, 0, currentPrimaryButtons.length);
cPB2[currentPrimaryButtons.length] = stdHelpButton;
currentPrimaryButtons = cPB2;
}
if ((secondaryOptions != null) && (secondaryOptions.length != 0)) {
currentSecondaryButtons = new Component [secondaryOptions.length];
for (int i = 0; i < secondaryOptions.length; i++) {
if (secondaryOptions[i] == NotifyDescriptor.YES_OPTION) {
currentSecondaryButtons[i] = stdYesButton;
} else if (secondaryOptions[i] == NotifyDescriptor.NO_OPTION) {
currentSecondaryButtons[i] = stdNoButton;
} else if (secondaryOptions[i] == NotifyDescriptor.OK_OPTION) {
currentSecondaryButtons[i] = stdOKButton;
} else if (secondaryOptions[i] == NotifyDescriptor.CANCEL_OPTION) {
currentSecondaryButtons[i] = stdCancelButton;
} else if (secondaryOptions[i] instanceof Component) {
currentSecondaryButtons[i] = (Component) secondaryOptions [i];
} else if (secondaryOptions [i] instanceof Icon) {
JButton button = new JButton ((Icon)secondaryOptions [i]);
currentSecondaryButtons[i] = button;
} else {
JButton button = new JButton (secondaryOptions[i].toString ());
currentSecondaryButtons[i] = button;
}
}
}
// -----------------------------------------------------------------------------
// Create panels for main (primary) and additional (secondary) buttons and add to content pane
if (currentAlign == DialogDescriptor.BOTTOM_ALIGN || currentAlign == -1) {
JPanel panelForPrimary = null;
JPanel panelForSecondary = null;
if (currentPrimaryButtons != null) {
panelForPrimary = new JPanel ();
if (currentAlign == -1) {
panelForPrimary.setLayout (new org.openide.awt.EqualFlowLayout ());
} else {
panelForPrimary.setLayout (new org.openide.awt.EqualFlowLayout (FlowLayout.RIGHT));
}
for (int i = 0; i < currentPrimaryButtons.length; i++) {
modifyListener (currentPrimaryButtons[i], buttonListener, true); // add button listener
panelForPrimary.add (currentPrimaryButtons[i]);
}
}
if (currentSecondaryButtons != null) {
panelForSecondary = new JPanel ();
panelForSecondary.setLayout (new org.openide.awt.EqualFlowLayout (FlowLayout.LEFT));
for (int i = 0; i < currentSecondaryButtons.length; i++) {
modifyListener (currentSecondaryButtons[i], buttonListener, true); // add button listener
panelForSecondary.add (currentSecondaryButtons[i]);
}
}
// both primary and secondary buttons are used
if ((panelForPrimary != null) && (panelForSecondary != null)) {
currentButtonsPanel = new JPanel ();
currentButtonsPanel.setLayout (new BorderLayout ());
currentButtonsPanel.add (panelForPrimary, BorderLayout.EAST);
currentButtonsPanel.add (panelForSecondary, BorderLayout.WEST);
} else if (panelForPrimary != null) {
currentButtonsPanel = panelForPrimary;
} else {
currentButtonsPanel = panelForSecondary;
}
// add final button panel to the dialog
if (currentButtonsPanel != null) {
getContentPane ().add (currentButtonsPanel, BorderLayout.SOUTH);
}
} else if (currentAlign == DialogDescriptor.RIGHT_ALIGN) {
currentButtonsPanel = new JPanel ();
currentButtonsPanel.setLayout (new GridBagLayout ());
GridBagConstraints gbc = new GridBagConstraints ();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1.0f;
gbc.insets = new Insets (5, 4, 2, 5);
gbc.fill = GridBagConstraints.HORIZONTAL;
if (currentPrimaryButtons != null) {
for (int i = 0; i < currentPrimaryButtons.length; i++) {
modifyListener (currentPrimaryButtons[i], buttonListener, true); // add button listener
currentButtonsPanel.add (currentPrimaryButtons[i], gbc);
}
}
GridBagConstraints padding = new GridBagConstraints ();
padding.gridwidth = GridBagConstraints.REMAINDER;
padding.weightx = 1.0f;
padding.weighty = 1.0f;
padding.fill = GridBagConstraints.BOTH;
currentButtonsPanel.add (new JPanel (), padding);
gbc.insets = new Insets (2, 4, 5, 5);
if (currentSecondaryButtons != null) {
for (int i = 0; i < currentSecondaryButtons.length; i++) {
modifyListener (currentSecondaryButtons[i], buttonListener, true); // add button listener
currentButtonsPanel.add (currentSecondaryButtons[i], gbc);
}
}
// add final button panel to the dialog
if (currentButtonsPanel != null) {
getContentPane ().add (currentButtonsPanel, BorderLayout.EAST);
}
}
updateDefaultButton ();
}
/** Checks default button and updates it
*/
private void updateDefaultButton () {
if (currentPrimaryButtons != null) {
// finds default button
for (int i = 0; i < currentPrimaryButtons.length; i++) {
if (currentPrimaryButtons[i] instanceof JButton) {
JButton b = (JButton)currentPrimaryButtons[i];
if (b.isVisible() && b.isEnabled () && b.isDefaultCapable()) {
getRootPane ().setDefaultButton(b);
return;
}
}
}
}
getRootPane ().setDefaultButton (null);
}
private void modifyListener (Component comp, ButtonListener l, boolean add) {
// on JButtons attach simply by method call
if (comp instanceof JButton) {
JButton b = (JButton)comp;
if (add) {
b.addActionListener (l);
b.addComponentListener(l);
b.addPropertyChangeListener(l);
} else {
b.removeActionListener (l);
b.removeComponentListener(l);
b.removePropertyChangeListener(l);
}
return;
} else {
// we will have to use dynamic method invocation to add the action listener
// to generic component (and we succeed only if it has the addActionListener method)
java.lang.reflect.Method m = null;
try {
m = comp.getClass ().getMethod (add ? "addActionListener" : "removeActionListener", new Class[] { ActionListener.class });// NOI18N
} catch (NoSuchMethodException e) {
m = null; // no jo, we cannot attach ActionListener to this Component
} catch (SecurityException e2) {
m = null; // no jo, we cannot attach ActionListener to this Component
}
if (m != null) {
try {
m.invoke (comp, new Object[] { l });
} catch (Exception e) {
// not succeeded, so give up
}
}
}
}
public void show () {
NbPresenter prev = currentModalDialog;
currentModalDialog = this;
super.show ();
currentModalDialog = prev;
}
public void propertyChange(final java.beans.PropertyChangeEvent evt) {
boolean update = false;
if (DialogDescriptor.PROP_OPTIONS.equals (evt.getPropertyName ())) {
initializeButtons ();
update = true;
} else if (DialogDescriptor.PROP_OPTION_TYPE.equals (evt.getPropertyName ())) {
initializeButtons ();
update = true;
} else if (DialogDescriptor.PROP_OPTIONS_ALIGN.equals (evt.getPropertyName ())) {
initializeButtons ();
update = true;
} else if (DialogDescriptor.PROP_MESSAGE.equals (evt.getPropertyName ())) {
initializeMessage ();
// In case change of help ID on component message:
updateHelp ();
update = true;
} else if (DialogDescriptor.PROP_MESSAGE_TYPE.equals (evt.getPropertyName ())) {
initializeMessage ();
update = true;
} else if (DialogDescriptor.PROP_TITLE.equals (evt.getPropertyName ())) {
setTitle (descriptor.getTitle ());
} else if (DialogDescriptor.PROP_HELP_CTX.equals (evt.getPropertyName ())) {
updateHelp ();
// In case buttons have changed: //just buttons!!
currentButtonsPanel.revalidate();
currentButtonsPanel.repaint();
}
if (update) {
getContentPane ().repaint ();
getContentPane ().validate ();
pack ();
setLocationRelativeTo (null);
}
}
public Dimension getMinimumSize () {
return new Dimension (400, 200);
}
private void updateHelp () {
//System.err.println ("Updating help for NbDialog...");
HelpCtx help = getHelpCtx ();
// Handle help from the inner component automatically (see docs
// in DialogDescriptor):
if (HelpCtx.DEFAULT_HELP.equals (help)) {
Object msg = descriptor.getMessage ();
if (msg instanceof Component) {
help = HelpCtx.findHelp ((Component) msg);
}
if (HelpCtx.DEFAULT_HELP.equals (help)) help = null;
}
if (! Utilities.compareObjects (currentHelp, help)) {
currentHelp = help;
if (help != null && help.getHelpID () != null) {
//System.err.println ("New help ID for root pane: " + help.getHelpID ());
HelpCtx.setHelpIDString (getRootPane (), help.getHelpID ());
}
// Refresh button list if it had already been created.
if (haveCalledInitializeButtons) initializeButtons ();
}
}
/** Options align.
*/
protected int getOptionsAlign () {
return -1;
}
/** Getter for button listener or null
*/
protected ActionListener getButtonListener () {
return null;
}
/** Closing options.
*/
protected Object[] getClosingOptions () {
return null;
}
/** Updates help.
*/
protected HelpCtx getHelpCtx () {
return null;
}
public void windowDeactivated(final java.awt.event.WindowEvent p1) {
}
public void windowClosed(final java.awt.event.WindowEvent p1) {
}
public void windowDeiconified(final java.awt.event.WindowEvent p1) {
}
public void windowOpened(final java.awt.event.WindowEvent p1) {
}
public void windowIconified(final java.awt.event.WindowEvent p1) {
}
public void windowClosing(final java.awt.event.WindowEvent p1) {
descriptor.setValue (NotifyDescriptor.CLOSED_OPTION);
dispose ();
}
public void windowActivated(final java.awt.event.WindowEvent p1) {
}
/** Button listener
*/
private class ButtonListener extends Object
implements ActionListener, java.awt.event.ComponentListener,
java.beans.PropertyChangeListener {
public void actionPerformed (ActionEvent evt) {
Object pressedOption = evt.getSource ();
// handle ESCAPE
if (evt.getActionCommand() == CANCEL_COMMAND) {
pressedOption = NotifyDescriptor.CLOSED_OPTION;
} else {
if (evt.getSource () == stdHelpButton) {
String sysprop = System.getProperty ("org.openide.actions.HelpAction.DEBUG"); // NOI18N
if ("true".equals (sysprop) || "full".equals (sysprop)) // NOI18N
System.err.println ("Help button showing: " + currentHelp); // NOI18N, please do not comment out
TopManager.getDefault ().showHelp (currentHelp);
return;
}
Object[] options = descriptor.getOptions ();
if (
options != null &&
currentPrimaryButtons != null &&
options.length == currentPrimaryButtons.length
) {
for (int i = 0; i < currentPrimaryButtons.length; i++) {
if (evt.getSource () == currentPrimaryButtons[i]) {
pressedOption = options[i];
}
}
}
options = descriptor.getAdditionalOptions ();
if (
options != null &&
currentSecondaryButtons != null &&
options.length == currentSecondaryButtons.length
) {
for (int i = 0; i < currentSecondaryButtons.length; i++) {
if (evt.getSource () == currentSecondaryButtons[i]) {
pressedOption = options[i];
}
}
}
if (evt.getSource () == stdYesButton) {
pressedOption = NotifyDescriptor.YES_OPTION;
} else if (evt.getSource () == stdNoButton) {
pressedOption = NotifyDescriptor.NO_OPTION;
} else if (evt.getSource () == stdCancelButton) {
pressedOption = NotifyDescriptor.CANCEL_OPTION;
} else if (evt.getSource () == stdOKButton) {
pressedOption = NotifyDescriptor.OK_OPTION;
}
}
descriptor.setValue (pressedOption);
ActionListener al = getButtonListener ();
if (al != null) {
if (pressedOption == evt.getSource ()) {
al.actionPerformed (evt);
} else {
al.actionPerformed (new ActionEvent (
pressedOption, evt.getID (), evt.getActionCommand (), evt.getModifiers ()
));
}
}
Object[] arr = getClosingOptions ();
if (arr == null || pressedOption == NotifyDescriptor.CLOSED_OPTION) {
// all options should close
setVisible (false);
} else {
java.util.List l = java.util.Arrays.asList (arr);
if (l.contains (pressedOption)) {
setVisible (false);
}
}
}
public void componentShown(final java.awt.event.ComponentEvent p1) {
updateDefaultButton ();
}
public void componentResized(final java.awt.event.ComponentEvent p1) {
}
public void componentHidden(final java.awt.event.ComponentEvent p1) {
updateDefaultButton ();
}
public void componentMoved(final java.awt.event.ComponentEvent p1) {
}
public void propertyChange(final java.beans.PropertyChangeEvent p1) {
if ("enabled".equals (p1.getPropertyName())) {
updateDefaultButton ();
}
}
}
}
/*
* Log
* 12 Gandalf 1.11 1/18/00 Jaroslav Tulach Solves deadlock on
* Solaris 1.2.1
* 11 Gandalf 1.10 1/17/00 Petr Kuzel Buttons revalidating
* fixed.
* 10 Gandalf 1.9 1/14/00 Jaroslav Tulach #5308
* 9 Gandalf 1.8 1/13/00 Jaroslav Tulach I18N
* 8 Gandalf 1.7 1/9/00 Jaroslav Tulach Again and better.
* 7 Gandalf 1.6 1/9/00 Jaroslav Tulach Stupid bug in finding
* pressed option.
* 6 Gandalf 1.5 1/7/00 David Simonek better settings of dialog
* owners
* 5 Gandalf 1.4 1/7/00 Jesse Glick Debugging for Patrick.
* 4 Gandalf 1.3 1/5/00 Jaroslav Tulach Supports custom options
* 3 Gandalf 1.2 1/5/00 Jesse Glick Fixed bug with Help
* button replacing rather than adding to default OK/Cancel.
* 2 Gandalf 1.1 1/4/00 Jesse Glick Help button on right of
* dialogs, not left.
* 1 Gandalf 1.0 12/30/99 Jaroslav Tulach
* $
* Log
* 12 Gandalf 1.11 1/18/00 Jaroslav Tulach Solves deadlock on
* Solaris 1.2.1
* 11 Gandalf 1.10 1/17/00 Petr Kuzel Buttons revalidating
* fixed.
* 10 Gandalf 1.9 1/14/00 Jaroslav Tulach #5308
* 9 Gandalf 1.8 1/13/00 Jaroslav Tulach I18N
* 8 Gandalf 1.7 1/9/00 Jaroslav Tulach Again and better.
* 7 Gandalf 1.6 1/9/00 Jaroslav Tulach Stupid bug in finding
* pressed option.
* 6 Gandalf 1.5 1/7/00 David Simonek better settings of dialog
* owners
* 5 Gandalf 1.4 1/7/00 Jesse Glick Debugging for Patrick.
* 4 Gandalf 1.3 1/5/00 Jaroslav Tulach Supports custom options
* 3 Gandalf 1.2 1/5/00 Jesse Glick Fixed bug with Help
* button replacing rather than adding to default OK/Cancel.
* 2 Gandalf 1.1 1/4/00 Jesse Glick Help button on right of
* dialogs, not left.
* 1 Gandalf 1.0 12/30/99 Jaroslav Tulach
* $
*/